package com.dpiinc.TechPage.repository
import androidx.annotation.MainThread
import androidx.lifecycle.MutableLiveData
import androidx.paging.PagedList
import com.dpiinc.TechPage.AIWriteSettings
import com.dpiinc.TechPage.api.NoteListApi
import com.dpiinc.TechPage.api.PagingRequestHelper
import com.dpiinc.TechPage.api.asyncSubscribe
import com.dpiinc.TechPage.api.createStatusLiveData
import com.dpiinc.TechPage.model.NoteListBean
import com.dpiinc.TechPage.room.bean.NoteEntity
import com.dpiinc.TechPage.utils.DateUtils
import java.util.concurrent.Executor

/**
 * This boundary callback gets notified when user reaches to the edges of the list such that the
 * database cannot provide any more data.
 * <p>
 * The boundary callback might be called multiple times for the same direction so it does its own
 * rate limiting using the PagingRequestHelper class.
 */
class NoteListBoundaryCallback(
        private val noteListApi: NoteListApi,
        private val handleResponse: (NoteListBean?) -> Unit,
        private val ioExecutor: Executor,
        private val networkPageSize: Int)
    : PagedList.BoundaryCallback<NoteEntity>() {

    val helper = PagingRequestHelper(ioExecutor)
    val networkState = helper.createStatusLiveData()
    val totalCount = MutableLiveData<Int>()

    /**
     * Database returned 0 items. We should query the backend for more items.
     */
    @MainThread
    override fun onZeroItemsLoaded() {
        helper.runIfNotRunning(PagingRequestHelper.RequestType.INITIAL) { callback ->
            noteListApi.loadFirstPage(networkPageSize)
                    .asyncSubscribe({
                        totalCount.value = it.result.totalCount
                        insertItemsIntoDb(it.result, callback)
                    }, {
                        callback.recordFailure(it)
                    })
        }


    }

    /**
     * User reached to the end of the list.
     */
    @MainThread
    override fun onItemAtEndLoaded(itemAtEnd: NoteEntity) {
        helper.runIfNotRunning(PagingRequestHelper.RequestType.AFTER) { callback ->
            noteListApi.loadDataBefore(networkPageSize, itemAtEnd.noteId)
                    .asyncSubscribe({
                        insertItemsIntoDb(it.result, callback)
                    }, {
                        callback.recordFailure(it)
                    })
        }
    }


    /**
     * every time it gets new items, boundary callback simply inserts them into the database and
     * paging library takes care of refreshing the list if necessary.
     */
    private fun insertItemsIntoDb(
            noteList: NoteListBean,
            it: PagingRequestHelper.Request.Callback) {
        ioExecutor.execute {
            handleResponse(noteList)
            it.recordSuccess()
        }
    }

    override fun onItemAtFrontLoaded(itemAtFront: NoteEntity) {
        helper.runIfNotRunning(PagingRequestHelper.RequestType.BEFORE) { callback ->
            noteListApi.loadUpdate(networkPageSize, AIWriteSettings.getNoteListLatestGetTime())
                    .asyncSubscribe({
                        insertItemsIntoDb(it.result, callback)
                        AIWriteSettings.setNoteListLatestGetTime(DateUtils.getCurrentTimeMillis())
                    }, {
                        callback.recordFailure(it)
                    })
        }
    }
}